package edu.moravian.entity;

import edu.moravian.math.Point2D;
import edu.moravian.math.Vector2D;

/**
 *
 * @author Elliot
 *
 * This is the base class for all agents.
 */
public abstract class Entity
{
    protected Point2D location;
    protected Vector2D heading;
    protected double speed;
    protected double mass;
    protected double radius;
    protected String type;

    public Entity()
    {
    }




    protected Entity(Point2D location, Vector2D heading, double speed, double mass, double radius, String type)
    {
        this.location = location;
        this.heading = heading;
        this.speed = speed;
        this.mass = mass;
        this.radius = radius;
        this.type = type;
    }




    protected Entity(Point2D location, Vector2D velocity, double mass, double radius, String type)
    {
        this(location, velocity.getNormalized(), velocity.magnitude(), mass, radius, type);
    }




    /**
     * Set the location
     *
     * @param location the location to update to
     */
    public void setLocation(Point2D location)
    {

        this.location = location;
    }




    /**
     * Get the current location
     *
     * @return the location
     */
    public Point2D getLocation()
    {
        return location;
    }




    /**
     * Set the velocity
     *
     * @param velocity the velocity to update to
     */
    public void setVelocity(Vector2D velocity)
    {
        double newSpeed = velocity.magnitude();
        Vector2D newHeading = velocity.getNormalized();

        this.speed = newSpeed;

        this.heading = newHeading;
    }




    /**
     * Get the current velocity
     *
     * @return the velocity
     */
    public Vector2D getVelocity()
    {
        return heading.times(speed);
    }




    /**
     * Updates the agents heading and maintains the current speed. This expects
     * a normal vector as the heading or a zero vector
     *
     * @param heading a normal heading
     */
    public void setHeading(Vector2D heading)
    {
        if (heading.isNormal() == false && heading.equals(Vector2D.zero) == false)
        {
            throw new IllegalStateException("Set heading requires a normal vector");
        }

        this.heading = heading;
    }




    /**
     * Get the agents normal heading
     *
     * @return the normal heading
     */
    public Vector2D getHeading()
    {
        return heading;
    }




    /**
     * Updates the agent speed and maintains the current heading
     *
     * @param speed the new speed of the agent
     */
    public void setSpeed(double speed)
    {
        if (speed < 0)
        {
            throw new IllegalStateException("Speed must be >= 0");
        }

        this.speed = speed;
    }




    /**
     * Get the agents speed
     *
     * @return the agents speed
     */
    public double getSpeed()
    {
        return speed;
    }




    /**
     * Set the agents mass
     *
     * @param mass the updated mass
     */
    public void setMass(double mass)
    {
        if (mass < 0)
        {
            throw new IllegalStateException("mass must be positive");
        }

        this.mass = mass;
    }




    /**
     * Get the agents mass
     *
     * @return the agents mass
     */
    public double getMass()
    {
        return mass;
    }




    /**
     * Set the radius
     *
     * @param radius the new radius
     */
    public void setRadius(double radius)
    {
        if (radius < 0)
        {
            throw new IllegalStateException("Radius must be positive");
        }
        this.radius = radius;
    }




    public double getRadius()
    {
        return radius;
    }




    /**
     * Get the type or string description of the entity
     */
    public String getType()
    {
        return type;
    }




    /**
     * For all agents to implement their own update method
     *
     * @param delta
     */
    public abstract void update(double delta);




}



